import tkinter
import socket #导入TCP库
import threading
import datetime
from tkinter import messagebox
import os


status = 0
# http://tt.ai-thinker.com:8000/ttcloud    安信可透传云，测试TCP


def main_fun():
    try:
        global status
        global tcp_client
        global tcp_server
        # 创建tcp服务端套接字
        # 参数同客户端配置一致，这里不再重复
        tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # 设置端口号复用，让程序退出端口号立即释放，否则的话在30秒-2分钟之内这个端口是不会被释放的，这是TCP的为了保证传输可靠性的机制。
        tcp_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
        # 给客户端绑定端口号，客户端需要知道服务器的端口号才能进行建立连接。IP地址不用设置，默认就为本机的IP地址。
        server_ip = server_ip_entry.get()
        sever_port = int(server_port_entry.get())
        sever_addr = (server_ip, sever_port)
        tcp_server.bind(sever_addr)
        status_label.config(text='服务已开启,等待连接', bg='yellow')
        # 设置监听
        # 128:最大等待建立连接的个数， 提示： 目前是单任务的服务端，同一时刻只能服务与一个客户端，后续使用多任务能够让服务端同时服务与多个客户端
        # 不需要让客户端进行等待建立连接
        # listen后的这个套接字只负责接收客户端连接请求，不能收发消息，收发消息使用返回的这个新套接字tcp_client来完成
        tcp_server.listen(128)
        # 等待客户端建立连接的请求, 只有客户端和服务端建立连接成功代码才会解阻塞，代码才能继续往下执行
        # 1. 专门和客户端通信的套接字： tcp_client
        # 2. 客户端的ip地址和端口号： tcp_client_address
        tcp_client, tcp_client_address = tcp_server.accept()
        status = 1
        status_label.config(text='连接成功', bg='lightgreen')
        # 代码执行到此说明连接建立成功
        # print("客户端的ip地址和端口号:", tcp_client_address)
        # 接收客户端发送的数据, 这次接收数据的最大字节数是1024

        try:
            while status == 1:
                if status == 0:
                    break
                recv_data = tcp_client.recv(1024)
                if not recv_data:
                    break
                # recv_data = tcp_client.recv(1024)
                # 对服务器发来的数据进行解码保存到变量recv_content中
                recv_content = recv_data.decode(encoding="utf-8")
                # print("接收客户端的数据为:", recv_content)
                val1 = str(datetime.datetime.now()) + '   tcp received\n' + str(recv_content) + '\n'
                received_text.insert('end', val1)
        except:
            status_label.config(text='连接已断开', bg='yellow')
    except Exception as ex:
        messagebox.showerror(title='error', message=str(ex))


def thread_main_fun():
    thread_add1 = threading.Thread(target=main_fun)
    thread_add1.start()


def send_message():
    if status == 1:
        # 准备要发送给服务器的数据
        data1 = send_text.get(0.0, 'end')
        send_data = data1.encode(encoding="utf-8")

        # 发送数据给客户端
        tcp_client.send(send_data)
    else:
        messagebox.showwarning(title='warning', message='请先建立连接')


def disconnect():
    try:
        global status
        # 关闭服务端的套接字, 终止和客户端提供建立连接请求的服务 但是正常来说服务器的套接字是不需要关闭的，因为服务器需要一直运行。
        tcp_server.close()
        if status == 1:
            # 关闭服务与客户端的套接字， 终止和客户端通信的服务
            # print('套接字关闭')
            tcp_client.close()
            status_label.config(text='服务已关闭', bg='pink')
        status = 0
    except Exception as ex:
        messagebox.showerror(title='error', message=str(ex))


win = tkinter.Tk()
win.title('TCP server-side           Author : Shi Sixian')
win.geometry('780x400')
win.option_add('*Font', '宋体 10')

server_ip_label = tkinter.Label(win, text='ServerIP:')
server_ip_label.place(x=20, y=20)
server_ip_entry = tkinter.Entry(win, width=20)
server_ip_entry.place(x=90, y=20)
server_port_label = tkinter.Label(win, text='ServerPort:')
server_port_label.place(x=250, y=20)
server_port_entry = tkinter.Entry(win, width=8)
server_port_entry.place(x=335, y=20)
connect_button = tkinter.Button(win, text='Open', command=thread_main_fun)
connect_button.place(x=410, y=17)
disconnect_button = tkinter.Button(win, text='OFF', command=disconnect)
disconnect_button.place(x=490, y=17)
status_label = tkinter.Label(win, text='服务未开启', bg='yellow', width=25)
status_label.place(x=580, y=20)

server_ip_entry.insert('end', '127.0.0.1')
server_port_entry.insert('end', '61234')

frame1 = tkinter.Frame(win, width=360, height=330, bg='ivory')
frame1.place(x=20, y=50)
frame2 = tkinter.Frame(win, width=360, height=330, bg='ivory')
frame2.place(x=400, y=50)

send_label = tkinter.Label(frame1, text='Send massage to the client-side', bg='ivory')
send_label.place(x=5, y=5)
send_button = tkinter.Button(frame1, text='Send', command=send_message)
send_button.place(x=300, y=2)
send_text = tkinter.Text(frame1, width=49, height=23)
send_text.place(x=5, y=25)

received_label = tkinter.Label(frame2, text='Received massage from the client-side', bg='ivory')
received_label.place(x=5, y=5)
received_text = tkinter.Text(frame2, width=49, height=23)
received_text.place(x=5, y=25)


def quit1():
    os._exit(0)


win.resizable(False, False)
win.protocol("WM_DELETE_WINDOW", quit1)
win.mainloop()
